#ifndef REGISTER_HPP
#define REGISTER_HPP

#include <QObject>
#include <QMutex>
#include <QMutexLocker>
#include <QMetaType>
#include <math.h>
#include <limits.h>

/**
* @brief
*
* @class Register register.hpp "register.hpp"
*/
class Register : public QObject
{
    Q_OBJECT

public:
    explicit Register(QObject *parent = 0);

    /**
    * @brief Constructor for Register
    *
    * @fn explicit Register(int address, int bank, int standard = 0)
    * @param address
    * @param bank
    * @param standard
    */
    explicit Register(int address, int bank, int standard = 0);

    /**
    * @brief Copy Constructor for Register
    *
    * @fn Register(const Register &other)
    * @param other
    */
    Register(const Register &other);

    /**
    * @brief Destructor for Register
    *
    * @fn ~Register()
    */
    ~Register();

    /**
    * @brief Set a single Bit
    *
    * @fn virtual void setBit(int bit)
    * @param bit
    */
    virtual void setBit(int bit);

    /**
    * @brief Clear a single Bit
    *
    * @fn virtual void clearBit(int bit)
    * @param bit
    */
    virtual void clearBit(int bit);

    /**
    * @brief Check whether a specified bit is set
    *
    * @fn bool isSet(int bit) const
    * @param bit
    * @return bool
    */
    virtual bool isSet(int bit) const;

    /**
    * @brief Set the complete value for this Register
    *
    * @fn virtual void setValue(int value, bool force = false)
    * @param value
    * @param force
    */
    virtual void setValue(int value, bool force = false);

    /**
    * @brief Get the complete value for this Register
    *
    * @fn int getValue() const
    * @return int
    */
    virtual int getValue() const;

    /**
    * @brief Returns the bank of this Register
    *
    * @fn const int getBank() const
    * @return int
    */
    const int getBank() const;

    /**
    * @brief Returns the Address of this Register
    *
    * @fn const int getAddress() const
    * @return int
    */
    const int getAddress() const;

    /**
    * @brief Clear the Register
    *
    * @fn virtual void clear()
    */
    virtual void clear();

    /**
    * @brief Sets the Register to a standard value
    *
    * @fn virtual void reset()
    */
    virtual void reset();

    /**
    * @brief Returns the standard value of this register
    *
    * @fn int getStandard() const
    * @return int
    */
    int getStandard() const;

    /**
    * @brief Sets the standard value for a register
    *
    * @fn setStandard
    * @param standard
    */
    void setStandard(int standard);

    Register& operator++(int);

    Register& operator--(int);

    Register& operator<<(int digits);

    Register& operator>>(int digits);

    Register& operator+=(int value);

    Register& operator-=(int value);

    Register& operator&=(int value);

    Register& operator|=(int value);

    Register& operator^=(int value);

    bool operator==(int value);

    bool operator==(Register &reg);

    Register& operator+(int value);

    Register& operator-(int value);

    Register& operator&(int value);

    Register& operator|(int value);

    Register& operator^(int value);

    Register& operator=(int value);

    /**
    * @brief Get a textual representation of the internal value
    * @details If bit is not in the range 0-7, the complete value is returned as string
    * Otherwise only the specified bit is returned as String
    *
    * @fn QString toString(int bit = -1) const
    * @param bit
    * @return QString
    */
    QString toString(int bit = -1) const;

protected:
    int value;
    int standard;
    const int address;
    const int bank;
    QMutex *mutex;

signals:
    /**
    * @brief Signal is emitted when the internal data has changed
    *
    * @fn void contentChanged(int value)
    * @param value
    */
    void contentChanged(int value);

    /**
    * @brief Signal is emitted when intenal data changed
    * @details address and bank representing the location of this Register
    *
    * @fn void changed(int address, int bank)
    * @param address
    * @param bank
    */
    void changed(int address, int bank);

    /**
    * @brief Signal is emitted when register overflows
    *
    * @fn void registerOverflow()
    */
    void registerOverflow();

    /**
    * @brief Signal is emitted when register underflows
    *
    * @fn void registerUnderflow()
    */
    void registerUnderflow();

};

Q_DECLARE_METATYPE(Register);
Q_DECLARE_METATYPE(Register*);

#endif // REGISTER_HPP
